home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / guvenlik / syslinux-3.07.exe / com32 / lib / vsscanf.c < prev   
Encoding:
C/C++ Source or Header  |  2004-11-10  |  8.0 KB  |  366 lines

  1. /*
  2.  * vsscanf.c
  3.  *
  4.  * vsscanf(), from which the rest of the scanf()
  5.  * family is built
  6.  */
  7.  
  8. #include <ctype.h>
  9. #include <stdarg.h>
  10. #include <stddef.h>
  11. #include <inttypes.h>
  12. #include <string.h>
  13. #include <limits.h>
  14. #include <stdio.h>
  15.  
  16. #ifndef LONG_BIT
  17. #define LONG_BIT (CHAR_BIT*sizeof(long))
  18. #endif
  19.  
  20. enum flags {
  21.   FL_SPLAT  = 0x01,        /* Drop the value, do not assign */
  22.   FL_INV    = 0x02,        /* Character-set with inverse */
  23.   FL_WIDTH  = 0x04,        /* Field width specified */
  24.   FL_MINUS  = 0x08,        /* Negative number */
  25. };
  26.  
  27. enum ranks {
  28.   rank_char    = -2,
  29.   rank_short    = -1,
  30.   rank_int     = 0,
  31.   rank_long    = 1,
  32.   rank_longlong    = 2,
  33.   rank_ptr      = INT_MAX    /* Special value used for pointers */
  34. };
  35.  
  36. #define MIN_RANK    rank_char
  37. #define MAX_RANK    rank_longlong
  38.  
  39. #define INTMAX_RANK    rank_longlong
  40. #define SIZE_T_RANK    rank_long
  41. #define PTRDIFF_T_RANK    rank_long
  42.  
  43. enum bail {
  44.   bail_none = 0,        /* No error condition */
  45.   bail_eof,            /* Hit EOF */
  46.   bail_err            /* Conversion mismatch */
  47. };
  48.  
  49. static inline const char *
  50. skipspace(const char *p)
  51. {
  52.   while ( isspace((unsigned char)*p) ) p++;
  53.   return p;
  54. }
  55.  
  56. #undef set_bit
  57. static inline void
  58. set_bit(unsigned long *bitmap, unsigned int bit)
  59. {
  60.   bitmap[bit/LONG_BIT] |= 1UL << (bit%LONG_BIT);
  61. }
  62.  
  63. #undef test_bit
  64. static inline int
  65. test_bit(unsigned long *bitmap, unsigned int bit)
  66. {
  67.   return (int)(bitmap[bit/LONG_BIT] >> (bit%LONG_BIT)) & 1;
  68. }
  69.  
  70. int vsscanf(const char *buffer, const char *format, va_list ap)
  71. {
  72.   const char *p = format;
  73.   char ch;
  74.   const char *q = buffer;
  75.   const char *qq;
  76.   uintmax_t val = 0;
  77.   int rank = rank_int;        /* Default rank */
  78.   unsigned int width = UINT_MAX;
  79.   int base;
  80.   enum flags flags = 0;
  81.   enum {
  82.     st_normal,            /* Ground state */
  83.     st_flags,            /* Special flags */
  84.     st_width,            /* Field width */
  85.     st_modifiers,        /* Length or conversion modifiers */
  86.     st_match_init,        /* Initial state of %[ sequence */
  87.     st_match,            /* Main state of %[ sequence */
  88.     st_match_range,        /* After - in a %[ sequence */
  89.   } state = st_normal;
  90.   char *sarg = NULL;        /* %s %c or %[ string argument */
  91.   enum bail bail = bail_none;
  92.   int sign;
  93.   int converted = 0;        /* Successful conversions */
  94.   unsigned long matchmap[((1 << CHAR_BIT)+(LONG_BIT-1))/LONG_BIT];
  95.   int matchinv = 0;        /* Is match map inverted? */
  96.   unsigned char range_start = 0;
  97.  
  98.   while ( (ch = *p++) && !bail ) {
  99.     switch ( state ) {
  100.     case st_normal:
  101.       if ( ch == '%' ) {
  102.     state = st_flags;
  103.     flags = 0; rank = rank_int; width = UINT_MAX;
  104.       } else if ( isspace((unsigned char)ch) ) {
  105.     q = skipspace(q);
  106.       } else {
  107.     if ( *q == ch )
  108.       q++;
  109.     else
  110.       bail = bail_err;    /* Match failure */
  111.       }
  112.       break;
  113.  
  114.     case st_flags:
  115.       switch ( ch ) {
  116.       case '*':
  117.     flags |= FL_SPLAT;
  118.     break;
  119.       case '0' ... '9':
  120.     width = (ch-'0');
  121.     state = st_width;
  122.     flags |= FL_WIDTH;
  123.     break;
  124.       default:
  125.     state = st_modifiers;
  126.     p--;            /* Process this character again */
  127.     break;
  128.       }
  129.       break;
  130.  
  131.     case st_width:
  132.       if ( ch >= '0' && ch <= '9' ) {
  133.     width = width*10+(ch-'0');
  134.       } else {
  135.     state = st_modifiers;
  136.     p--;            /* Process this character again */
  137.       }
  138.       break;
  139.  
  140.     case st_modifiers:
  141.       switch ( ch ) {
  142.     /* Length modifiers - nonterminal sequences */
  143.       case 'h':
  144.     rank--;            /* Shorter rank */
  145.     break;
  146.       case 'l':
  147.     rank++;            /* Longer rank */
  148.     break;
  149.       case 'j':
  150.     rank = INTMAX_RANK;
  151.     break;
  152.       case 'z':
  153.     rank = SIZE_T_RANK;
  154.     break;
  155.       case 't':
  156.     rank = PTRDIFF_T_RANK;
  157.     break;
  158.       case 'L':
  159.       case 'q':
  160.     rank = rank_longlong;    /* long double/long long */
  161.     break;
  162.  
  163.       default:
  164.     /* Output modifiers - terminal sequences */
  165.     state = st_normal;    /* Next state will be normal */
  166.     if ( rank < MIN_RANK )    /* Canonicalize rank */
  167.       rank = MIN_RANK;
  168.     else if ( rank > MAX_RANK )
  169.       rank = MAX_RANK;
  170.  
  171.     switch ( ch ) {
  172.     case 'P':        /* Upper case pointer */
  173.     case 'p':        /* Pointer */
  174. #if 0    /* Enable this to allow null pointers by name */
  175.       q = skipspace(q);
  176.       if ( !isdigit((unsigned char)*q) ) {
  177.         static const char * const nullnames[] =
  178.         { "null", "nul", "nil", "(null)", "(nul)", "(nil)", 0 };
  179.         const char * const *np;
  180.  
  181.         /* Check to see if it's a null pointer by name */
  182.         for ( np = nullnames ; *np ; np++ ) {
  183.           if ( !strncasecmp(q, *np, strlen(*np)) ) {
  184.         val = (uintmax_t)((void *)NULL);
  185.         goto set_integer;
  186.           }
  187.         }
  188.         /* Failure */
  189.         bail = bail_err;
  190.         break;
  191.       }
  192.       /* else */
  193. #endif
  194.       rank = rank_ptr;
  195.       base = 0; sign = 0;
  196.       goto scan_int;
  197.  
  198.     case 'i':        /* Base-independent integer */
  199.       base = 0; sign = 1;
  200.       goto scan_int;
  201.  
  202.     case 'd':        /* Decimal integer */
  203.       base = 10; sign = 1;
  204.       goto scan_int;
  205.  
  206.     case 'o':        /* Octal integer */
  207.       base = 8; sign = 0;
  208.       goto scan_int;
  209.  
  210.     case 'u':        /* Unsigned decimal integer */
  211.       base = 10; sign = 0;
  212.       goto scan_int;
  213.       
  214.     case 'x':        /* Hexadecimal integer */
  215.     case 'X':
  216.       base = 16; sign = 0;
  217.       goto scan_int;
  218.  
  219.     case 'n':        /* Number of characters consumed */
  220.       val = (q-buffer);
  221.       goto set_integer;
  222.  
  223.     scan_int:
  224.       q = skipspace(q);
  225.       if ( !*q ) {
  226.         bail = bail_eof;
  227.         break;
  228.       }
  229.       val = strntoumax(q, (char **)&qq, base, width);
  230.       if ( qq == q ) {
  231.         bail = bail_err;
  232.         break;
  233.       }
  234.       q = qq;
  235.       converted++;
  236.       /* fall through */
  237.  
  238.     set_integer:
  239.       if ( !(flags & FL_SPLAT) ) {
  240.         switch(rank) {
  241.         case rank_char:
  242.           *va_arg(ap, unsigned char *) = (unsigned char)val;
  243.           break;
  244.         case rank_short:
  245.           *va_arg(ap, unsigned short *) = (unsigned short)val;
  246.           break;
  247.         case rank_int:
  248.           *va_arg(ap, unsigned int *) = (unsigned int)val;
  249.           break;
  250.         case rank_long:
  251.           *va_arg(ap, unsigned long *) = (unsigned long)val;
  252.           break;
  253.         case rank_longlong:
  254.           *va_arg(ap, unsigned long long *) = (unsigned long long)val;
  255.           break;
  256.         case rank_ptr:
  257.           *va_arg(ap, void **) = (void *)(uintptr_t)val;
  258.           break;
  259.         }
  260.       }
  261.       break;
  262.       
  263.     case 'c':               /* Character */
  264.           width = (flags & FL_WIDTH) ? width : 1; /* Default width == 1 */
  265.           sarg = va_arg(ap, char *);
  266.           while ( width-- ) {
  267.             if ( !*q ) {
  268.               bail = bail_eof;
  269.               break;
  270.             }
  271.             *sarg++ = *q++;
  272.           }
  273.           if ( !bail )
  274.             converted++;
  275.           break;
  276.  
  277.         case 's':               /* String */
  278.       {
  279.         char *sp;
  280.         sp = sarg = va_arg(ap, char *);
  281.         while ( width-- && *q && !isspace((unsigned char)*q) ) {
  282.           *sp++ = *q++;
  283.         }
  284.         if ( sarg != sp ) {
  285.           *sp = '\0';    /* Terminate output */
  286.           converted++;
  287.         } else {
  288.           bail = bail_eof;
  289.         }
  290.       }
  291.       break;
  292.       
  293.     case '[':        /* Character range */
  294.       sarg = va_arg(ap, char *);
  295.       state = st_match_init;
  296.       matchinv = 0;
  297.       memset(matchmap, 0, sizeof matchmap);
  298.       break;
  299.  
  300.     case '%':        /* %% sequence */
  301.       if ( *q == '%' )
  302.         q++;
  303.       else
  304.         bail = bail_err;
  305.       break;
  306.  
  307.     default:        /* Anything else */
  308.       bail = bail_err;    /* Unknown sequence */
  309.       break;
  310.     }
  311.       }
  312.       break;
  313.     
  314.     case st_match_init:        /* Initial state for %[ match */
  315.       if ( ch == '^' && !(flags & FL_INV) ) {
  316.     matchinv = 1;
  317.       } else {
  318.     set_bit(matchmap, (unsigned char)ch);
  319.     state = st_match;
  320.       }
  321.       break;
  322.       
  323.     case st_match:        /* Main state for %[ match */
  324.       if ( ch == ']' ) {
  325.     goto match_run;
  326.       } else if ( ch == '-' ) {
  327.     range_start = (unsigned char)ch;
  328.     state = st_match_range;
  329.       } else {
  330.     set_bit(matchmap, (unsigned char)ch);
  331.       }
  332.       break;
  333.       
  334.     case st_match_range:        /* %[ match after - */
  335.       if ( ch == ']' ) {
  336.     set_bit(matchmap, (unsigned char)'-'); /* - was last character */
  337.     goto match_run;
  338.       } else {
  339.     int i;
  340.     for ( i = range_start ; i < (unsigned char)ch ; i++ )
  341.       set_bit(matchmap, i);
  342.     state = st_match;
  343.       }
  344.       break;
  345.  
  346.     match_run:            /* Match expression finished */
  347.       qq = q;
  348.       while ( width && *q && test_bit(matchmap, (unsigned char)*q)^matchinv ) {
  349.     *sarg++ = *q++;
  350.       }
  351.       if ( q != qq ) {
  352.     *sarg = '\0';
  353.     converted++;
  354.       } else {
  355.     bail = *q ? bail_err : bail_eof;
  356.       }
  357.       break;
  358.     }
  359.   }
  360.  
  361.   if ( bail == bail_eof && !converted )
  362.     converted = -1;        /* Return EOF (-1) */
  363.  
  364.   return converted;
  365. }
  366.